package com.societyGames.codeAlong.state.codeExercise.view.libraryTree
{
import com.societyGames.codeAlong.localization.StringManager;
import com.societyGames.codeAlong.state.codeExercise.model.ClassData;
import com.societyGames.codeAlong.state.codeExercise.model.FunctionData;
import com.societyGames.codeAlong.state.codeExercise.model.FunctionParameterData;
import com.societyGames.codeAlong.state.codeExercise.model.FunctionReturnData;
import com.societyGames.codeAlong.state.codeExercise.model.LibraryData;
import com.societyGames.codeAlong.state.codeExercise.model.TermData;
import com.societyGames.flashForms.TreeViewContainer;
import com.societyGames.flashForms.TreeViewNode;
import com.societyGames.flashForms.basicSkin.BasicAssets;
import com.societyGames.flashForms.basicSkin.SharedTextFields;
import com.societyGames.system.EventObject;

import flash.display.Bitmap;
import flash.display.DisplayObject;
import flash.events.TextEvent;
import flash.text.AntiAliasType;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;

public class LibraryTree extends TreeViewContainer
{
  private var _linkEventObject:EventObject;

  private var _functionsNode:TreeViewNode;
  private var _classesNode:TreeViewNode;

  public function LibraryTree()
  {
    this._linkEventObject = new EventObject(this, TextEvent.LINK);
  }

  public function populateLibrary(libraryData:LibraryData):void
  {
    populateFunctions(libraryData.functions);
    populateClasses(libraryData.classes);
  }

  //For the UI to point at it.
  public function get functionsNode():TreeViewNode
  {
    return _functionsNode;
  }

  //For the UI to point at it.
  public function get classesNode():TreeViewNode
  {
    return _classesNode;
  }

  /**
   * This allows adding functions.
   * @param functionDatas The data to be added as nodes.
   */
  public function populateFunctions(functionDatas:Vector.<FunctionData>):void
  {
    if (functionDatas == null || functionDatas.length == 0)
    {
      return;
    }

    var functionNodeAdded:Boolean;
    if (_functionsNode == null)
    {
      _functionsNode = createNode(StringManager.getString("functionsNode"));
      functionNodeAdded = true;
    }

    for each (var functionData:FunctionData in functionDatas)
    {
      _functionsNode.treeViewContainer.addNode(createFunctionNode(functionData));
    }

    if (functionNodeAdded)
    {
      this.addNode(_functionsNode);
    }
  }

  /**
   * This allows adding classes.
   * @param classDatas The data to be added as nodes.
   */
  public function populateClasses(classDatas:Vector.<ClassData>):void
  {
    if (classDatas == null || classDatas.length == 0)
    {
      return;
    }

    var classNodeAdded:Boolean;
    if (_classesNode == null)
    {
      _classesNode = createNode("Classes");
      classNodeAdded = true;
    }

    for each (var classData:ClassData in classDatas)
    {
      _classesNode.treeViewContainer.addNode(createClassNode(classData));
    }

    if (classNodeAdded)
    {
      this.addNode(_classesNode);
    }
  }

  public function populateTerms(termDatas:Vector.<TermData>):void
  {
    var termsNode:TreeViewNode = createTermsNode(termDatas);
    if (termsNode != null)
    {
      this.addNode(termsNode);
    }
  }

  public function get linkEventObject():EventObject
  {
    return this._linkEventObject;
  }

  private function createTextField(text:String, link:String = null):TextField
  {
    var textField:TextField = SharedTextFields.createHtmlTextField();
    textField.selectable = false;
    textField.autoSize = TextFieldAutoSize.LEFT;
    textField.antiAliasType = AntiAliasType.ADVANCED;
    if (link != null)
    {
      textField.htmlText = "<p><a href=\"event:" + link + "\">" + text + "</a></p>";
    }
    else
    {
      textField.htmlText = "<p>" + text + "</p>";
    }
    return textField;
  }

  private function createNode(text:String, link:String = null):TreeViewNode
  {
    var expanded:Bitmap = new BasicAssets.TreeExpandedClass();
    var collapsed:Bitmap = new BasicAssets.TreeCollapsedClass();
    var node:TreeViewNode = new TreeViewNode(Math.max(expanded.width, collapsed.width), expanded, collapsed);
    node.child = createTextField(text, link);
    return node;
  }

  private function createFunctionNode(functionData:FunctionData):TreeViewNode
  {
    var text:String = functionData.name + "(";
    var isFirst:Boolean = true;
    for each (var parameterData:FunctionParameterData in functionData.parameters)
    {
      if (!isFirst)
      {
        text += ",";
      }
      text += parameterData.name + (parameterData.type.length > 0 ? ":" + parameterData.type : "");
      isFirst = false;
    }
    text += "):" + functionData.returnData.type;
    var node:TreeViewNode = createNode(text, functionData.toLink());
    return node;
  }

  private function createReturnNode(returnData:FunctionReturnData):DisplayObject
  {
    return this.createTextField("return:" + returnData.type, returnData.toLink());
  }

  private function createParameterNode(parameterData:FunctionParameterData):TreeViewNode
  {
    return createNode(parameterData.name + (parameterData.type.length > 0 ? ":" + parameterData.type : ""), parameterData.toLink());
  }

  private function createClassNode(classData:ClassData):TreeViewNode
  {
    var node:TreeViewNode = createNode(classData.name, classData.toLink());
    for each (var fieldData:FunctionParameterData in classData.fields)
    {
      node.treeViewContainer.addNode(createNode(fieldData.name, fieldData.toLink()));
    }
    for each (var methodData:FunctionData in classData.methods)
    {
      node.treeViewContainer.addNode(createFunctionNode(methodData));
    }
    return node;
  }

  private function createTermsNode(termDatas:Vector.<TermData>):TreeViewNode
  {
    var node:TreeViewNode;
    if (termDatas.length > 0)
    {
      node = createNode(StringManager.getString("termsNode"));
      for each (var termData:TermData in termDatas)
      {
        node.treeViewContainer.addNode(createTermNode(termData));
      }
    }
    return node;
  }

  private function createTermNode(termData:TermData):DisplayObject
  {
    return createTextField(termData.term, termData.toLink());
  }
}
}